﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using System.Globalization;

namespace MvcImproved.Generic.Controls
{
	[ParseChildren(false)]
	[PersistChildren(true)]
	public class Checkbox<TDataItem, TMemberValue> : GenericInputControl<TDataItem, TMemberValue>
	{
		public Checkbox(Func<TDataItem, TMemberValue> valueMember)
			: base(valueMember, "checkbox")
		{
			TypeConverter converter = TypeDescriptor.GetConverter(typeof(TMemberValue));
			if (typeof(TMemberValue) == typeof(bool))
				Value = (TMemberValue)(object)true;
			else if (converter.CanConvertFrom(typeof(bool)))
				Value = (TMemberValue)converter.ConvertFrom(true);
			else if (converter.CanConvertFrom(typeof(int)))
				Value = (TMemberValue)converter.ConvertFrom(1);

			RenderChildrenFirst = false;
		}

		public TMemberValue Value
		{
			get;
			set;
		}

		public bool Checked
		{
			get;
			set;
		}

		public string Text
		{
			get { return Label; }
			set { Label = value; }
		}

		protected override void ControlSpecificRender(HtmlTextWriter writer, SortedDictionary<string, string> attrs)
		{
			if (!DesignMode)
			{
				int? attemptedValue = (int?)GetModelStateValue(Name, typeof(int));
				bool? attemptedBoolValue = (bool?)GetModelStateValue(Name, typeof(bool));

				if (attemptedValue != null)
				{
					// Never format the attempted value since it was already formatted in the previous request
					if ((int)attemptedValue > 0)
						attrs.Add("checked", "checked");
				}
				else if (attemptedBoolValue.HasValue && attemptedBoolValue.Value)
					attrs.Add("checked", "checked");
				else
				{
					// Use an explicit value attribute if it is available. Otherwise get it from ViewData.
					TMemberValue objectValue = ValueMemberLambda(DataValue);
					bool isChecked = Checked;

					TypeConverter converter = TypeDescriptor.GetConverter(typeof(TMemberValue));
					if (converter.CanConvertTo(typeof(bool)))
						isChecked = (bool)converter.ConvertTo(objectValue, typeof(bool));
					else if (converter.CanConvertTo(typeof(int)))
						isChecked = (int)converter.ConvertTo(objectValue, typeof(int)) > 0;
					else
					{
						bool boolValue = Convert.ToBoolean(objectValue);
						isChecked = boolValue;
					}

					// The HtmlTextWriter will automatically encode this value
					if (isChecked)
						attrs.Add("checked", "checked");
				}
			}
			attrs["value"] = Value.ToString();
		}
	}

	// Non-generic version of the control that's used in the actual markup
	[ControlBuilder(typeof(GenericControlBuilder))]
	[GenericControlType(typeof(Checkbox<,>), MemberValue = "ValueMember", GenericParameters = "ModelType")]
	[ParseChildren(false)]
	[PersistChildren(true)]
	public class Checkbox : Checkbox<object, object>
	{
		public Checkbox()
			: base(null)
		{ }

		public string ModelType
		{
			get;
			set;
		}
	}
}
